[Monte Carlo] SnowflakeとMonte Carloの接続を設定する #MonteCarloData
Monte CarloとSnowflakeを接続する方法を紹介します。
Monte Carloとデータウェアハウスを接続すると、テーブルとパイプラインの状態を追跡できるようになります。メタデータ、クエリ ログ、メトリクスをウェアハウスから自動的に取得することで、データパイプラインの状態を可視化しています。
1. SnowflakeでMonte Carlo用のサービスアカウントを作成する
公式ドキュメントにある以下のクエリを実行すれば作成できます。
まず、下記クエリでこれ以降に使用するクエリの変数を定義します。ハイライトを入れている3行目と7行目はユーザー側で任意のパスワードとデータベース名を入力します。他にもユーザー名、ウェアハウス名、ロール名も任意の名前にしたい場合には=(イコール)の右側を書き換えます。
-- Configuration set mc_username='MONTE_CARLO'; set mc_password='<monte_carlo_password>'; set mc_warehouse_size='XSMALL'; set mc_warehouse_name='MONTE_CARLO_WH'; set mc_role_name='MONTE_CARLO_ROLE'; set database_to_monitor='<your_database>';
パスワードとデータベースを入力したら、以下のクエリをすべて実行します。
-- 権限付与用にロールを設定 USE ROLE ACCOUNTADMIN; -- Monte Carloのモニタリングワークロード用にウェアハウスを作成 CREATE WAREHOUSE IF NOT EXISTS identifier($mc_warehouse_name) WAREHOUSE_SIZE=$mc_warehouse_size INITIALLY_SUSPENDED=TRUE AUTO_SUSPEND = 5 AUTO_RESUME = TRUE; -- ユーザーMONTE_CARLOが使用するロールを作成 CREATE ROLE IF NOT EXISTS identifier($mc_role_name); -- モンテカルロ用ユーザー(MONTE_CARLO)の作成と、ロール(MONTE_CARLO_ROLE)の付与 CREATE USER IF NOT EXISTS identifier($mc_username) PASSWORD=$mc_password DEFAULT_ROLE=$mc_role_name; GRANT ROLE identifier($mc_role_name) TO USER identifier($mc_username); -- 新たなウェアハウス(MONTE_CARLO_WH)を使用する権限を付与 GRANT OPERATE, USAGE, MONITOR ON WAREHOUSE identifier($mc_warehouse_name) TO ROLE identifier($mc_role_name); -- クエリ履歴へのアクセス権を付与 GRANT IMPORTED PRIVILEGES ON DATABASE "SNOWFLAKE" TO ROLE identifier($mc_role_name); -- モニター対象のデータベースおよびスキーマのメタデータにアクセスできる権限を付与 GRANT USAGE,MONITOR ON DATABASE identifier($database_to_monitor) TO ROLE identifier($mc_role_name); GRANT USAGE,MONITOR ON ALL SCHEMAS IN DATABASE identifier($database_to_monitor) TO ROLE identifier($mc_role_name); -- スキーマにfuture grantsが付与されているかを確認 ※参考を参照 USE DATABASE identifier($database_to_monitor); CREATE OR REPLACE PROCEDURE GRANT_REFERENCES_TO_MONTE_CARLO() RETURNS VARCHAR LANGUAGE javascript EXECUTE AS CALLER AS $$ snowflake.createStatement({sqlText: `use database identifier($database_to_monitor)`}).execute(); var show_future_grants = snowflake.createStatement({sqlText: `SHOW FUTURE GRANTS IN DATABASE identifier($database_to_monitor)`}).execute(); var schema_future_grants = snowflake.createStatement({sqlText: `select * from TABLE(RESULT_SCAN('${show_future_grants.getQueryId()}')) where "grant_on" = 'SCHEMA'`}).execute(); if (schema_future_grants.getRowCount() > 0) { var schemas_to_grant = snowflake.createStatement({ sqlText:`select * from information_schema.SCHEMATA where SCHEMA_NAME <> 'INFORMATION_SCHEMA'`}).execute(); var granted_schemas = ""; while(schemas_to_grant.next()) { table_schema = schemas_to_grant.getColumnValue("SCHEMA_NAME"); snowflake.createStatement({ sqlText:`GRANT REFERENCES ON ALL TABLES IN SCHEMA ${table_schema} TO ROLE identifier($mc_role_name)`}).execute(); snowflake.createStatement({ sqlText:`GRANT REFERENCES ON ALL VIEWS IN SCHEMA ${table_schema} TO ROLE identifier($mc_role_name)`}).execute(); snowflake.createStatement({ sqlText:`GRANT REFERENCES ON ALL EXTERNAL TABLES IN SCHEMA ${table_schema} TO ROLE identifier($mc_role_name)`}).execute(); snowflake.createStatement({ sqlText:`GRANT REFERENCES ON FUTURE TABLES IN SCHEMA ${table_schema} TO ROLE identifier($mc_role_name)`}).execute(); snowflake.createStatement({ sqlText:`GRANT REFERENCES ON FUTURE VIEWS IN SCHEMA ${table_schema} TO ROLE identifier($mc_role_name)`}).execute(); snowflake.createStatement({ sqlText:`GRANT REFERENCES ON FUTURE EXTERNAL TABLES IN SCHEMA ${table_schema} TO ROLE identifier($mc_role_name)`}).execute(); granted_schemas += table_schema + "; " } return `Granted references for schemas ${granted_schemas}`; } snowflake.createStatement({ sqlText: `GRANT REFERENCES ON ALL TABLES IN DATABASE identifier($database_to_monitor) TO ROLE identifier($mc_role_name)`}).execute(); snowflake.createStatement({ sqlText: `GRANT REFERENCES ON ALL VIEWS IN DATABASE identifier($database_to_monitor) TO ROLE identifier($mc_role_name)`}).execute(); snowflake.createStatement({ sqlText: `GRANT REFERENCES ON ALL EXTERNAL TABLES IN DATABASE identifier($database_to_monitor) TO ROLE identifier($mc_role_name)`}).execute(); snowflake.createStatement({ sqlText: `GRANT REFERENCES ON FUTURE TABLES IN DATABASE identifier($database_to_monitor) TO ROLE identifier($mc_role_name)`}).execute(); snowflake.createStatement({ sqlText: `GRANT REFERENCES ON FUTURE VIEWS IN DATABASE identifier($database_to_monitor) TO ROLE identifier($mc_role_name)`}).execute(); snowflake.createStatement({ sqlText: `GRANT REFERENCES ON FUTURE EXTERNAL TABLES IN DATABASE identifier($database_to_monitor) TO ROLE identifier($mc_role_name)`}).execute(); return `Granted references for database`; $$; CALL GRANT_REFERENCES_TO_MONTE_CARLO(); -- モニター対象のデータベースに読み取り専用(SELECT権限のみ)の権限を付与 GRANT SELECT ON ALL TABLES IN DATABASE identifier($database_to_monitor) TO ROLE identifier($mc_role_name); GRANT SELECT ON ALL VIEWS IN DATABASE identifier($database_to_monitor) TO ROLE identifier($mc_role_name); GRANT SELECT ON ALL EXTERNAL TABLES IN DATABASE identifier($database_to_monitor) TO ROLE identifier($mc_role_name); GRANT SELECT ON ALL STREAMS IN DATABASE identifier($database_to_monitor) TO ROLE identifier($mc_role_name); GRANT USAGE ON FUTURE SCHEMAS IN DATABASE identifier($database_to_monitor) TO ROLE identifier($mc_role_name); -- スキーマにfuture grantsが付与されているかを確認 ※参考を参照 USE DATABASE identifier($database_to_monitor); CREATE OR REPLACE PROCEDURE GRANT_SELECT_FUTURES_TO_MONTE_CARLO() RETURNS VARCHAR LANGUAGE javascript EXECUTE AS CALLER AS $$ snowflake.createStatement({sqlText: `use database identifier($database_to_monitor)`}).execute(); var show_future_grants = snowflake.createStatement({sqlText: `SHOW FUTURE GRANTS IN DATABASE identifier($database_to_monitor)`}).execute(); var schema_future_grants = snowflake.createStatement({sqlText: `select * from TABLE(RESULT_SCAN('${show_future_grants.getQueryId()}')) where "grant_on" = 'SCHEMA'`}).execute(); if (schema_future_grants.getRowCount() > 0) { var schemas_to_grant = snowflake.createStatement({ sqlText:`select SCHEMA_NAME from information_schema.SCHEMATA where SCHEMA_NAME <> 'INFORMATION_SCHEMA'`}).execute(); var granted_schemas = ""; while(schemas_to_grant.next()) { table_schema = schemas_to_grant.getColumnValue("SCHEMA_NAME"); snowflake.createStatement({ sqlText:`GRANT SELECT ON FUTURE TABLES IN SCHEMA ${table_schema} TO ROLE identifier($mc_role_name)`}).execute(); snowflake.createStatement({ sqlText:`GRANT SELECT ON FUTURE VIEWS IN SCHEMA ${table_schema} TO ROLE identifier($mc_role_name)`}).execute(); snowflake.createStatement({ sqlText:`GRANT SELECT ON FUTURE EXTERNAL TABLES IN SCHEMA ${table_schema} TO ROLE identifier($mc_role_name)`}).execute(); snowflake.createStatement({ sqlText:`GRANT SELECT ON FUTURE STREAMS IN SCHEMA ${table_schema} TO ROLE identifier($mc_role_name)`}).execute(); granted_schemas += table_schema + ";" } return `Granted future select for schemas ${granted_schemas}`; } snowflake.createStatement({ sqlText:`GRANT SELECT ON FUTURE TABLES IN DATABASE identifier($database_to_monitor) TO ROLE identifier($mc_role_name)`}).execute(); snowflake.createStatement({ sqlText:`GRANT SELECT ON FUTURE VIEWS IN DATABASE identifier($database_to_monitor) TO ROLE identifier($mc_role_name)`}).execute(); snowflake.createStatement({ sqlText:`GRANT SELECT ON FUTURE EXTERNAL TABLES IN DATABASE identifier($database_to_monitor) TO ROLE identifier($mc_role_name)`}).execute(); snowflake.createStatement({ sqlText:`GRANT SELECT ON FUTURE STREAMS IN DATABASE identifier($database_to_monitor) TO ROLE identifier($mc_role_name)`}).execute(); return `Granted future select for database`; $$; CALL GRANT_SELECT_FUTURES_TO_MONTE_CARLO();
※参考(https://docs.snowflake.com/ja/sql-reference/sql/grant-privilege#considerations)
データベースとスキーマに対するfuture grantが重複する場合、スキーマに対するfuture grantが優先されるというのがSnowflakeの仕様としてあるため、対象のデータベースにすでにスキーマに対するfuture grantがあるかどうかを確認しています。
2. Monte CarloでSnowflakeの情報を入力して接続する
Snowflake側でMonte Carlo用のユーザーが作成できたら、Monte Carloの画面でSnowflakeの接続情報を入力します。
Settings > Integrations > Data Lake and Warehouses > Create > Snowflake を選択
以下の入力フォームが出てくるので、ユーザー名などSnowflakeで作成したものを入力します。コネクション名はMonte Carloで管理しやすい任意の名前を入力します。
- Connection Name
- Account
- Warehouse
- MONTE_CARLO_WH
- User
- MONTE_CARLO
- Password
- ユーザー作成時に設定したパスワード
すべて入力して、テストが通れは接続は完了です。
アカウント名取得に苦戦
今回トライアルアカウントからの設定だったため、Account名でかなり引っかかってしまいました。アカウント名なのでログイン時のURLのsnowflakecomputing.comの前を持ってくればいいと思っていたのですが、ずっとError: 250001 (n/a): Could not connect to Snowflake backend after 0 attempt(s).Aborting
というエラーが出続けて心が折れました。
試しにselect current_account();
を実行したところ、ログイン用のURLとは全然違うものが出てきて自分の間違いに気づきました。
こういうAPIのアカウント名で引っかかった際には、まず、Snowsight画面の管理 > アカウント で対象のアカウントの行のロケーターという項目にマウスオーバーするとコピーマークが出てくるので、それをコピーします。コピーしたURLの`https://`以降と`.snowflakecomputing.com`より前の部分がアカウント名となります。(Snowflakeをホストしているクラウドとリージョンが入っていればそれがアカウント名です。)
参考:こちらからSnowflakeをホストしているクラウドとリージョンを見つけて、Account Identifierを確認できます。(例:AWSの東京リージョンならap-northeast-1.aws
)
自動でテーブル情報を収集
接続して2週間ほどでMonte Carloが接続しているデータベースの情報を学習して、Assetsページにデータの取得情報などをまとめてくれます。
まとめ
Monte CarloをSnowflakeと連携する方法のご紹介でした!